//
// Created by d on 6/5/16.
//

#include "common.h"
#include "classifier.h"
#include <boost/filesystem/operations.hpp>

using google::INFO;
using google::WARNING;
using google::ERROR;
using google::FATAL;
using std::stringstream;
using boost::filesystem::path;

TEST(CommonImage, CHECK_MAP_VAL) {
    Mat testmat = Mat::zeros(10, 10, CV_8UC3);
    testmat += cv::Scalar(255, 255, 255);
    ASSERT_EQ(testmat.depth(), CV_8U);
    ASSERT_EQ(testmat.channels(), 3);
    CommonImage commonImage(testmat);
    ASSERT_EQ(testmat.at<uchar>(0, 0), 255);
    Mat a = commonImage.getDouble().getOriginal();
    Mat b = commonImage.getDouble().getOriginal();
    ASSERT_EQ(a.depth(), CV_32F);
    ASSERT_EQ(a.channels(), 3);
    ASSERT_EQ(a.data, b.data);
    for (int x = 0; x < 10; x++)
        for (int y = 0; y < 10; y++) {
            ASSERT_EQ(a.at<cv::Vec3f>(0, 0).val[0], 1);
            ASSERT_EQ(a.at<cv::Vec3f>(0, 0).val[1], 1);
            ASSERT_EQ(a.at<cv::Vec3f>(0, 0).val[2], 1);
        }
}

TEST(LMDBDataSet, ConcurrencyTest) {
    LMDBDataSet lmdbDataSet;
    vector<Sample> randMat;
    cv::Mat mean = cv::Mat::zeros(1, 1, CV_64FC1);
    cv::Mat sigma = cv::Mat::ones(1, 1, CV_64FC1);
    const int numit = 1000;
    const int matSize = 100;
    // generate original data
    for (int i = 0; i < numit; i++) {
        Mat mat = Mat::zeros(matSize, matSize, CV_8UC3);
        cv::randn(mat, mean, sigma);
        ASSERT_EQ(mat.depth(), CV_8U);
        ASSERT_EQ(mat.channels(), 3);
        Sample sample{
                .data = mat,
                .label = i * i
        };
        randMat.push_back(sample);
    }
    // add data to lmdb
    path DBPath("concurrency_test_db");
    if (boost::filesystem::exists(DBPath)) {
        CHECK(boost::filesystem::remove_all(DBPath)) << "Error Remove Dir";
    }
    lmdbDataSet.newDB(DBPath.string());
    for (int i = 0; i < randMat.size(); i++) {
        lmdbDataSet.addSample(randMat[i]);
    }
    lmdbDataSet.close();
    // reopen the database and read all things out
    LOG(INFO) << "start Reading";
    lmdbDataSet.loadFromLMDB(DBPath.string());
    for (int i = 0; i < randMat.size(); i++) {
        Sample sample = lmdbDataSet[i];
        ASSERT_EQ(sample.label, randMat[i].label);
        ASSERT_EQ(cv::sum(sample.data != randMat[i].data).val[0], 0);
    }
}

TEST(Permutation, PermutationTest) {
    for (int testIter = 0; testIter < 100; testIter++) {
        int size = rand() % 50000;
        map<int, bool> visited;
        Permutation pm(size);
        for (int i = 0; i < size; i++) {
            ASSERT_EQ(visited.find(pm.current()), visited.end());
            visited[pm.current()] = true;
            pm.next();
        }
    }
}


int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    backward::SignalHandling sh;
    if (!sh.loaded()) {
        LOG(INFO) << "Load fiailed";
    }
    return RUN_ALL_TESTS();
}
